home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / build / compile.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  12.7 KB  |  356 lines

  1. (* Copyright 1989,1991,1992 by AT&T Bell Laboratories *)
  2.  
  3. (* Modules compiler for New Jersey ML.  Nick Rothwell, LFCS, January 1989,
  4.  *
  5.  * revised and simplified by Andrew Appel, 1990. 
  6.  *
  7.  * Modified to support separate compilation with free
  8.  * structure references. Also, code supporting import
  9.  * command has been isolated for easy removal. (erg)
  10.  *
  11.  * "import" code has been removed, old ModuleComp code has been
  12.  * incorporated, and name of functor has been changed to CompileUnit
  13.  * from Importer.  Changed to use first-class environments and
  14.  * to provide a minimal compilation interface to support separate
  15.  * compilation.
  16.  *)
  17.  
  18. signature COMPILEUNIT =
  19. sig
  20.   type staticUnit
  21.   type codeUnit
  22.   type compUnit
  23.   val changeLvars: staticUnit -> staticUnit
  24.   val elaborateUnit: Source.inputSource * Environment.staticEnv -> staticUnit
  25.   val parseUnit: Source.inputSource * Environment.staticEnv 
  26.          -> Ast.dec * Environment.staticEnv
  27.   val compileUnit: Source.inputSource * Environment.staticEnv -> compUnit
  28.   val compileAst: Ast.dec * Environment.staticEnv * Source.inputSource option
  29.                   -> compUnit
  30.   val executeUnit: 
  31.     compUnit * Environment.environment -> Environment.environment
  32. end
  33.  
  34. functor CompileUnit(structure Machm : CODEGENERATOR) : COMPILEUNIT =
  35. struct
  36.   open PrintUtil Access Modules Environment Lambda
  37.  
  38.   type componentId = InverseEnv.componentId
  39.  
  40.   type staticUnit = {staticEnv: staticEnv,
  41.              boundLvars: lvar list}
  42.  
  43.   type codeUnit =   {executable: System.Code.code,
  44.              imports: componentId list}
  45.  
  46.   type compUnit =   staticUnit * codeUnit
  47.  
  48.   type looker = lvar -> System.Unsafe.object
  49.   type result = System.Unsafe.object vector
  50.  
  51.   (* A single exception for all compilation failures. *)
  52.   exception Compile = System.Compile.Compile
  53.  
  54.   fun fail msg = raise (Compile msg)
  55.  
  56.  (* changeLvars:
  57.   * Rename the lvars of the static module.
  58.   * For each module binding, a fresh lvar will be chosen; hence
  59.   * at run-time, several imports of the same structure will presumably
  60.   * lead to a new copy of the code of that structure.
  61.   * Collect new import info.
  62.   *)
  63.   fun changeLvars ({staticEnv={static,...}, boundLvars}: staticUnit) : staticUnit =
  64.       let val newlvars = map (fn _ => mkLvar()) boundLvars
  65.            (* New lvars to be bound to module values. *)
  66.  
  67.       (* use intmap for translating lvars if there are many of them. *)
  68.       val lvarcount = length boundLvars
  69.       val lookup =
  70.           if lvarcount < 8
  71.           then (fn x =>
  72.               let fun f(a::ar, b::br) = if a=x then b else f(ar,br)
  73.                 | f _ = ErrorMsg.impossible "CompileUnit 1"
  74.                in f(boundLvars,newlvars)
  75.               end)
  76.           else
  77.           let val table = Intmap.new(lvarcount, Compile("changeLvars"))
  78.           val add = Intmap.add table
  79.           fun fill_table([],_) = ()
  80.             | fill_table(old::l,new::m) = (add(old,new); fill_table(l,m))
  81.            in fill_table(boundLvars,newlvars);
  82.           Intmap.map table
  83.           end
  84.  
  85.       val newstatenv = ref(StaticEnv.empty)
  86.       val newinvenv = ref(InverseEnv.empty)
  87.  
  88.       fun adjustBinding(_,FCTbind(FCTvar{name,access=PATH[lvar], binding})) = 
  89.         let val newlvar = lookup lvar
  90.             val newbind = FCTbind(FCTvar{name = name, access= PATH[newlvar],
  91.                          binding = binding})
  92.          in newinvenv :=
  93.              InverseEnv.bind(newlvar,
  94.                      {name=name,
  95.                       pid=ModuleUtil.getFctStamp binding,
  96.                       ty=TransBinding.transFctLty binding},
  97.                      !newinvenv);
  98.             newstatenv := StaticEnv.bind(name, newbind, !newstatenv)
  99.         end
  100.         | adjustBinding(_,STRbind(STRvar{name,access=PATH[lvar], binding})) =
  101.         let val newlvar = lookup lvar
  102.             val newbind = STRbind(STRvar{name = name, access= PATH[newlvar],
  103.                          binding = binding})
  104.          in newinvenv :=
  105.              InverseEnv.bind(newlvar,
  106.                      {name=name,
  107.                       pid=ModuleUtil.getStrStamp binding,
  108.                       ty=TransBinding.transStrLty binding},
  109.                      !newinvenv);
  110.             newstatenv := StaticEnv.bind (name, newbind, !newstatenv)
  111.         end
  112.         | adjustBinding(n,b as SIGbind _) =
  113.             newstatenv := StaticEnv.bind(n,b,!newstatenv)
  114.         | adjustBinding _ = ErrorMsg.impossible "CompileUnit 2"
  115.  
  116.        in StaticEnv.app adjustBinding static;
  117.       {staticEnv={static= !newstatenv, inverse= !newinvenv},boundLvars=newlvars}
  118.       end
  119.  
  120.  
  121.  (* kosherModuleDecl:
  122.   * Check that the declarations in the compilation unit are only
  123.   * structures, signatures and functors.
  124.   *)
  125.   fun kosherModuleDecl decl =
  126.       case decl
  127.     of Absyn.FCTdec _ => ()
  128.      | Absyn.SIGdec _ => ()
  129.      | Absyn.STRdec _ => ()
  130.      | Absyn.MARKdec(dec,_,_) => kosherModuleDecl dec
  131.      | Absyn.SEQdec decs => app kosherModuleDecl decs
  132.      | _ => fail "expecting signatures/structures/functors"
  133.  
  134.  
  135.   (* parsing *)
  136.  
  137.   fun elaborateUnit(source: Source.inputSource, {static=parseEnv,...}: staticEnv)
  138.                : staticUnit =
  139.       let val parser = Elaborate.parse (fn dec => dec) source
  140.  
  141.       (* Loop on top-level declarations, allowing
  142.        * only signature, structure, and functor bindings.
  143.        *)
  144.           fun loop(Elaborate.EOF, env, lvars) = (env, lvars)
  145.         | loop(Elaborate.ABORT, _,_) = fail "syntax error"
  146.         | loop(Elaborate.ERROR, _,_) = fail "syntax or semantic error"
  147.         | loop(Elaborate.PARSE(absyn,env'), env, lvars) =
  148.         let val _ = kosherModuleDecl absyn
  149.             val newLvars = Linkage.getvars absyn
  150.             val newenv = StaticEnv.atop(env',env)
  151.             val fullEnv = StaticEnv.atop(newenv,parseEnv)
  152.          in loop(parser fullEnv, newenv, newLvars@lvars)
  153.         end
  154.  
  155.       val (env, lvars) =
  156.         loop(parser(parseEnv),StaticEnv.empty,[])
  157.           handle Io x => (fail("unexpected: Io("^x^")"))
  158.                | exn as (Compile _) => raise exn
  159.                | exn => fail("compile-time exception: "
  160.                      ^ System.exn_name exn)
  161.  
  162.        in {staticEnv=makeStaticEnv(StaticEnv.consolidate env), boundLvars=lvars}
  163.       end  (* elaborateUnit *)
  164.  
  165.   fun parseUnit(source: Source.inputSource, {static=parseEnv,...}: staticEnv)
  166.                : Ast.dec * staticEnv =
  167.       let val parser = Parse.parse (fn dec => dec) source
  168.  
  169.       (* Loop on top-level declarations, allowing
  170.        * only signature, structure, and functor bindings.
  171.        *)
  172.           fun loop(Parse.EOF,ast, env) = (ast,env)
  173.         | loop(Parse.ABORT,_, _) = fail "syntax error"
  174.         | loop(Parse.ERROR,_, _) = fail "syntax or semantic error"
  175.         | loop(Parse.PARSE(ast',env'),ast, env) =
  176.         let val newenv = StaticEnv.atop(env',env)
  177.             val newast = ast' :: ast
  178.             val fullEnv = StaticEnv.atop(newenv,parseEnv)
  179.          in loop(parser fullEnv, newast,newenv)
  180.         end
  181.  
  182.       val (ast,env) =
  183.         loop(parser(parseEnv),[],StaticEnv.empty)
  184.           handle Io x => (fail("unexpected: Io("^x^")"))
  185.                | exn as (Compile _) => raise exn
  186.                | exn => fail("compile-time exception: "
  187.                      ^ System.exn_name exn)
  188.  
  189.       in
  190.       (Ast.SeqDec ast,makeStaticEnv(StaticEnv.consolidate env))
  191.       end (* parseUnit *)
  192.  
  193.  
  194.   (* compiling *)
  195.  
  196.   fun mkLambda (statenv, err, errMatch, anyErrors, dec) =
  197.       (Translate.transDec statenv err errMatch dec)
  198.       before
  199.       (if !anyErrors then fail "error during translate" else ())
  200.  
  201.   fun close(lvars,t,lexp) =
  202.       let val v = mkLvar()
  203.       fun doit(lv::rest,n) = APP(FN(lv,BOGUSty,doit(rest,n+1)), 
  204.                                      SELECT(n, VAR v))
  205.         | doit(nil, _) = lexp
  206.        in FN(v, t, doit(lvars, 0))
  207.       end
  208.  
  209.  (* Close and fold down all the lambdas, generate code.
  210.   * Also, use close to wrap with lambda abstractions binding free structure
  211.   * references.
  212.   *)
  213.   fun compileLambda (openLambda,importLvars,imports,getty) =
  214.     let val lt = RECORDty(map getty importLvars)
  215.         val lambda' = close(importLvars, lt, openLambda)
  216.     val finalLambda = Opt.closetop(lambda', !CoreInfo.corePath, getty)
  217.     val mash = #1 o Convert.convert o Reorder.reorder o LambdaOpt.lambdaopt
  218.     val executable = Machm.generate(mash finalLambda, NONE,
  219.             (fn _ => fn s => 
  220.               (app System.Print.say["Real constant out of range: ",s,"\n"];
  221.                fail "code generation failed")))
  222.      in {executable=System.Code.mkCode executable, imports=imports}
  223.     end
  224.  
  225.   fun loopAst (ast,env,src) = 
  226.     let val (anyErrors,error,errorMatch) = 
  227.         case src
  228.           of NONE =>
  229.           let val anyErrors = ref false
  230.            in (anyErrors,
  231.                ErrorMsg.errorNoFile(ErrorMsg.defaultConsumer(), anyErrors),
  232.                fn _ => "Match error")
  233.           end
  234.            | SOME source =>
  235.           (#anyErrors source, ErrorMsg.error source,
  236.            ErrorMsg.matchErrorString source)
  237.     val (absyn,newEnv) = 
  238.           ElabStr.elaborateTop (ast,env,error,errorMatch,fn dec => dec)
  239.     val _ = kosherModuleDecl absyn
  240.     val newLvars = Linkage.getvars absyn
  241.     val fullEnv = StaticEnv.atop(newEnv,env)
  242.     val newLambda = mkLambda(fullEnv,error,errorMatch,anyErrors,absyn)
  243.      in (newEnv,newLambda,newLvars)
  244.     end
  245.  
  246.   fun loopSource (source,compEnv,_) =
  247.       let val parser = Elaborate.parse (fn dec => dec) source
  248.       val initialLambda =
  249.         mkLambda(StaticEnv.empty, ErrorMsg.error source,
  250.              ErrorMsg.matchErrorString source, #anyErrors source,
  251.              Absyn.SEQdec nil)
  252.  
  253.       (* Loop on top-level declarations, allowing
  254.        * only signature, structure, and functor bindings.
  255.        *)
  256.           fun loop(Elaborate.EOF, env, lambda, lvars) = (env, lambda, lvars)
  257.         | loop(Elaborate.ABORT, _,_,_) = fail "syntax error"
  258.         | loop(Elaborate.ERROR, _,_,_) = fail "syntax or semantic error"
  259.         | loop(Elaborate.PARSE (absyn,env'), env, lambda, lvars) =
  260.         let val _ = kosherModuleDecl absyn
  261.             val newLvars = Linkage.getvars absyn
  262.             val newenv = StaticEnv.atop(env',env)
  263.             val fullEnv = StaticEnv.atop(newenv,compEnv)
  264.                     val _ = Index.report source (absyn, fullEnv)
  265.             val newLambda = 
  266.               mkLambda(fullEnv, ErrorMsg.error source,
  267.                                    ErrorMsg.matchErrorString source,
  268.                    #anyErrors source, absyn)
  269.          in loop(parser fullEnv, newenv, lambda o newLambda,
  270.              newLvars@lvars)
  271.         end
  272.       in loop(parser(compEnv),StaticEnv.empty,initialLambda,[]) end
  273.  
  274.   fun compileObj loop (object,{static=compEnv,inverse}: staticEnv,src) =
  275.       let val (env, lambda, lvars) =
  276.         loop(object,compEnv,src)
  277.           handle Io x => (fail("unexpected: Io("^x^")"))
  278.                | exn as (Compile _) => raise exn
  279.                | exn => fail("compile-time exception: "
  280.                          ^ System.exn_name exn)
  281.  
  282.           val newenv = makeStaticEnv(StaticEnv.consolidate env)
  283.       val static = {staticEnv=newenv, boundLvars=lvars}
  284.       val openLambda = lambda(Lambda.RECORD(map Lambda.VAR lvars))
  285.       val freelvars = Opt.freevars openLambda
  286.       val invlook = InverseEnv.look inverse
  287.       fun mapfree([],x,y) = (x,y)
  288.         | mapfree(lv::r,x,y) =
  289.             mapfree((r, invlook lv :: x, lv :: y)
  290.             handle InverseEnv.Unbound => (r,x,y))
  291.       val (importcomps,importlvars) = mapfree(freelvars,[],[])
  292.  
  293.           val getty = CompUtil.gengetty inverse
  294.  
  295.       val code = compileLambda(openLambda,importlvars,importcomps,getty)
  296.        in (static, code)
  297.       end  (* compileObj *)
  298.  
  299.   fun compileAst (ast,env,src : Source.inputSource option) =
  300.       let val ({staticEnv={static,inverse}, boundLvars},code) =
  301.         compileObj loopAst (ast,env,src)
  302.        in ({staticEnv = {static = static, inverse = inverse},
  303.         boundLvars = boundLvars},
  304.        code)
  305.       end
  306.  
  307.  (* compileUnit:
  308.   * Compile a unit from an instream, producing a compUnit.
  309.   *)
  310.  
  311.   fun compileUnit(source,env) = compileObj loopSource (source,env,NONE)
  312.  
  313.  
  314.   (* executing *)
  315.  
  316.   fun executeCode({executable,imports}, environ: environment) : result =
  317.       let val look_dyn = DynamicEnv.look (#dynamic environ)
  318.       val me: looker -> result -> result = System.Code.apply executable
  319.       fun nameOf s = 
  320.           (Symbol.nameSpaceToString(Symbol.nameSpace s))^" "^(Symbol.name s)
  321.       fun getImport {name,pid,ty} =
  322.           (case StaticEnv.look (#static environ, name)
  323.          of STRbind(STRvar{access=PATH[lv],binding,...}) =>
  324.               if (ModuleUtil.getStrStamp binding) = pid then (look_dyn lv)
  325.               else fail ("structure "^(nameOf name)^" has wrong stamp")
  326.           | FCTbind(FCTvar{access=PATH[lv],binding,...}) =>
  327.               if (ModuleUtil.getFctStamp binding) = pid then (look_dyn lv)
  328.               else fail ("functor "^(nameOf name)^" has wrong stamp")
  329.           | _ => ErrorMsg.impossible "ModuleComp.getImport"
  330.           ) handle StaticEnv.Unbound =>
  331.              fail((nameOf name)^
  332.                   " is not found in the loading environment")
  333.              | _ => fail "error while executing module"
  334.       val importRecord = Vector.vector (map getImport imports) 
  335.        in me look_dyn importRecord
  336.        handle exn => fail("uncaught exception "^ System.exn_name exn)
  337.       end
  338.  
  339.  (* executeUnit:
  340.   * Execute the code to produce the new values (result).
  341.   * The lvars are bound to the new values to form a new
  342.   * dynamic environment which is combined with the new static
  343.   * environment to form the result environment (bindEnv).
  344.   *)
  345.   fun executeUnit(({staticEnv={static,inverse},boundLvars}, code): compUnit,
  346.           environ: environment)
  347.         : environment =
  348.       let val result = executeCode(code,environ)
  349.        in (* PrintDec.printBindingTbl static; -- no printing! *)
  350.       bindEnv(static, inverse, boundLvars, result, emptyEnv)
  351.       end
  352.  
  353. end (* functor CompileUnit *)
  354.  
  355.  
  356.